<?php
/**
 * Zb数据拉取类
 * Author: zengdeshun
 * 2018-6-11 21:10:47
 */
namespace platform\driver\zb;
use think\Log;
use Workerman\Connection\AsyncTcpConnection;
use Workerman\Lib\Timer;
use platform\driver\Driver;
use exception\Platform as PlatformException;
use exception\Zb as ZbException;

class Zb extends Driver
{
    /**
     * rest api接口地址
     * @var string
     */
    private $api = '';

    private $tradeApi = '';

    /**
     * webSocket接口地址
     * @var string
     */
    private $stream = '';

    /**
     * API 访问密钥
     * @var string
     */
    private $accessKey = '';

    /**
     * 签名密钥
     * @var string
     */
    private $secretKey = '';

    /**
     * api请求路径
     * @var string
     */
    private $apiMethod = '';

    /**
     * api请求方法
     * @var string
     */
    private $reqMethod = '';
    /**
     * 中比特接口配置
     * @var array
     */
    private $config = [];

    public function __construct($param = [])
    {
        $this->config = file_get_contents(dirname(__FILE__) . '/config.json');
        $this->config = json_decode($this->config, true);
        $this->api = $this->config['api'];
        $this->tradeApi = $this->config['trade_api'];
        $this->stream = $this->config['stream'];
        if (isset($param['access_key']) && isset($param['secret_key'])) {
            $this->accessKey = $param['access_key'];
            $this->secretKey = $param['secret_key'];
        } else {
            $this->accessKey = $this->config['access_key'];
            $this->secretKey = $this->config['secret_key'];
        }
    }

    /**
     * 获取ZB最新市场配置数据
     * @return array
     * @throws \Exception
     */
    public function markets()
    {
        $path  = '/data/v1/markets';
        $data = curl($this->api . $path, [], 'GET', ["Content-type: application/x-www-form-urlencoded"]);
        return $data;
    }

    /**
     * 获取用户信息
     * @return array
     * @throws \Exception
     */
    public function accounts()
    {
        try {
            $this->apiMethod  = '/api/getAccountInfo';
            $this->reqMethod = 'get';
            $param = [
                'accesskey' => $this->accessKey,
                'method'    => 'getAccountInfo'
            ];
            $param = $this->createSign($param);
            $data = curl($this->tradeApi .  $this->apiMethod , $param, $this->reqMethod, ['application/x-www-form-urlencoded']);
            $data = json_decode($data, true);
            if(isset($data['code'])){
                if (array_key_exists($data['code'], $this->_errorCode)) {
                    $code = str_replace('-', '_', $this->_errorCode[$data['code']]);
                    exception(ZbException::getErrorMsg($code), $code, 'exception\Zb');
                    Log::record('关联账户失败，错误码' .  $this->_errorCode[$data['code']] . '错误信息' . $data['message']);
                }
            }
            return $data;
        } catch (\Exception $e) {
            exception(PlatformException::getErrorMsg(PlatformException::E_GET_ACCOUNT_ERROR), PlatformException::E_GET_ACCOUNT_ERROR, 'exception\Platform');
        }
    }

    /**
     * 委托下单
     * @param $type 交易类型1/0[buy/sell]
     * @param $symbol
     * @param $price
     * @param $amount
     * @return array
     * @throws \Exception
     */
    public function buy(...$data)
    {

        list($symbol, $quantity, $price, $type) = $data;
        if($type == 'buy'){
            $type = 1 ;
        }else{
            $type = 0 ;
        }
        $path  = '/api/order';
        $param = [
            'method'    => 'order',
            'accesskey' => $this->accessKey,
            'price'     => $price,
            'amount'    => $quantity,
            'tradeType' => $type,
            'currency'  => $symbol,
            'acctType'  => 0 //现货交易
        ];

        $param = $this->createSign($param);
        $data = curl($this->tradeApi . $path, $param, 'GET', ['application/x-www-form-urlencoded']);
        $data = json_decode($data,true);
        if($data['code'] == 1000){
            return $data['id'];
        } else {
            if (array_key_exists($data['code'], $this->_errorCode)) {
                $code = str_replace('-', '_', $this->_errorCode[$data['code']]);
                exception(ZbException::getErrorMsg($code), $code, 'exception\Zb');
                Log::record('Zb下单失败，错误码' .  $this->_errorCode[$data['code']] . '错误信息' . $data['code']);
            }
        }
    }

    /**
     * 取消委托
     * @param $orderId
     * @param $symbol
     * @return array
     * @throws \Exception
     */
    public function cancel(...$data)
    {
        list($orderId, $symbol) = $data;
        $path  = '/api/cancelOrder';
        $param = [
            'method'    => 'cancelOrder',
            'accesskey' => $this->accessKey,
            'id'        => $orderId,
            'currency'  => $symbol,
        ];

        $param = $this->createSign($param);
        $data = curl($this->tradeApi . $path, $param, 'GET', ['application/x-www-form-urlencoded']);
        $data = json_decode($data,true);

        if($data['code'] == 1000){
            return $data;
        } else {
            if (array_key_exists($data['code'], $this->_errorCode)) {
                $code = str_replace('-', '_', $this->_errorCode[$data['code']]);
                exception(ZbException::getErrorMsg($code), $code, 'exception\Zb');
                Log::record('Zb撤单失败，错误码' .  $this->_errorCode[$data['code']] . '错误信息' . $data['code']);
            }
        }
    }

    /**
     * 获取委托买单或卖单
     * @param $orderId
     * @param $symbol
     * @return array
     * @throws \Exception
     */
    public function order(...$data)
    {
        list($orderId, $symbol) = $data;
        $path  = '/api/getOrder';
        $param = [
            'method'    => 'getOrder',
            'accesskey' => $this->accessKey,
            'id'        => $orderId,
            'currency'  => $symbol,
        ];
        $param = $this->createSign($param);
        $data = curl($this->tradeApi . $path, $param, 'GET', ['application/x-www-form-urlencoded']);
        $data = json_decode($data, true);
        return $data;
    }

    /**
     * 参数签名
     * @param $params
     * @return mixed
     */
    public function createSign($params)
    {
        ksort($params);
        $tPreSign  = http_build_query($params, '', '&');
        $secretKey = sha1($this->secretKey);
        $tSign = hash_hmac('md5', $tPreSign, $secretKey);
        $params['sign'] = $tSign;
        $params['reqTime'] = time() * 1000;
        return $params;
    }

    /**
     * webSocket订阅ticker数据
     * @param $symbol
     * @param $callback
     * @return bool
     */
    public function detail($symbols, $callback)
    {
        $param = [];
        foreach ($symbols as $symbol => $value) {
            $symbolList = explode('_', $symbol);
            $symbol  = $symbolList[0].$symbolList[1];
            $param[]  =  [
                'event'   => 'addChannel',
                'channel' => "{$symbol}_ticker",
            ];
        }
        $this->webSocketClient($param, $callback);
        return true;
    }

    public function depth(array $symbols, callable $callback): bool
    {
        $param = [];

        foreach ($symbols as $symbol => $value) {
            $symbolList = explode('_', $symbol);
            $symbol  = $symbolList[0].$symbolList[1];

            $param[] = [
                'event'   => 'addChannel',
                'channel' => "{$symbol}_depth"
            ];
        }

        $this->webSocketClient($param, $callback);
        return true;
    }

    /**
     * webSocket接口统一请求客户端
     * @param $param
     * @param $callback
     * @return bool
     */
    protected function webSocketClient($param, $callback)
    {
        try {
            $con = new AsyncTcpConnection($this->stream);
        } catch (\Exception $e) {
            Log::record('请求webSocket接口出错 ' . $this->stream . $e->getMessage());
        }
        $con->transport = 'ssl'; // 设置以ssl加密方式访问，使之成为wss
        $con->onConnect = function ($con) use ($param) {
            if (!empty($param)) {
                if (is_array($param)) {
                    foreach ($param as $value) {
                        $con->send(json_encode($value));
                    }
                } else {
                    $con->send(json_encode($param));
                }
            }
        };

        $con->onMessage = function ($con, $data) use ($callback) {
            call_user_func_array($callback, array($data));
        };

        $con->connect();
        return true;
    }

    /**
     * Describe : 获取交易对
     * Anthor :  xxxxxxx
     * Date   : 2018/8/2320:25
     * param  :
     * return :
     *
     */
    public function symbols(){
       $data =  $this->markets();
        return $data ;
    }
    public  $_errorCode = [
        '1001'  =>  '34003',
        '1002'  =>  '34004',
        '1003'  =>  '34005',
        '1004'  =>  '34006',
        '1005'  =>  '34007',
        '1009'  =>  '34008',
        '1010'  =>  '34009',
        '1012'  =>  '34010',
        '1013'  =>  '34011',
        '2002'  =>  '34012',
        '2003'  =>  '34013',
        '2005'  =>  '34014',
        '2006'  =>  '34015',
        '2007'   => '34016',
        '2009'   =>  '34017',
        '3001'   =>  '34018',
        '3002'   =>  '34019',
        '3003'   =>  '34020',
        '3004'   =>  '34021',
        '3005'   =>  '34022',
        '3007'   =>  '34023',
        '3008'   =>  '34024',
        '4001'   =>  '34025',
        '4002'   =>  '34026',
        '3006'   => '34027'
    ];

    /**
     * REST方式获取行情
     * @return array
     * @throws \Exception
     */
    public function restTicker()
    {
        $path  = '/data/v1/allTicker';
        $data = curl($this->api . $path, [], 'GET', ["Content-type: application/x-www-form-urlencoded"]);
        $data = json_decode($data, true);
        return $data;
    }

    /**
     * REST方式获取深度
     * @param $symbol
     * @return array
     * @throws \Exception
     */
    public function restDepth($symbol)
    {
        $path  = "/data/v1/depth?market={$symbol}&size=10";
        $data = curl($this->api . $path, [], 'GET', ["Content-type: application/x-www-form-urlencoded"]);
        $data = json_decode($data, true);
        return $data;
    }
}